from abc import ABC, abstractmethod
from typing import List, Dict, Any, Optional

from src.core.backtest.context import Context
from src.core.indicators.indicator import Indicator, RequiresIndicators
from src.core.instruction.instruction import Instruction
from src.core.strategy.sizer.sizer import Sizer
from src.core.strategy.stop_loss.stop_loss_manager import StopLossManager
from src.core.strategy.take_profit.take_profit_manager import TakeProfitManager
from src.enums.enums import Direction
from src.enums.timeframe import Timeframe


class Strategy(ABC):
    """
    策略的抽象基类 (Abstract Base Class)。

    这是一个“装配图”和“规则手册”，而非一个包含所有逻辑的“上帝类”。
    它的核心职责是：
    1. 【声明依赖】: 清晰地声明运行所需的数据，包括时间周期和技术指标。
    2. 【组装组件】: 在初始化时，将具体的Alpha因子和风险管理组件组装起来。
    3. 【提供核心逻辑】: 提供计算最终Alpha信号的方法。
    4. 【定义高级行为】: (可选) 通过回调方法，定义在特定事件（如止损）
                      发生时的特殊处理逻辑，以实现复杂的交易行为。
    """

    def __init__(
            self,
            sizer: Sizer,
            stop_loss_manager: Optional[StopLossManager] = None,
            take_profit_manager: Optional[TakeProfitManager] = None
    ):
        """
        通过依赖注入 (Dependency Injection) 的方式来组装一个完整的策略。

        Args:
            sizer (ISizer): 
                一个仓位规模管理器，负责计算每次交易的数量。

            stop_loss_manager (Optional[List[StopLossManager]]):
                一个可选的止损管理器。如果没有，则不设置止损。

            take_profit_manager (Optional[List[TakeProfitManager]]):
                一个可选的止盈管理器。如果没有，则不设置止盈。
        """
        # --- [阶段 2: 组装组件] ---
        # 将传入的组件实例保存为策略的属性
        self.sizer = sizer
        self.stop_loss_manager = stop_loss_manager
        self.take_profit_manager = take_profit_manager

    @abstractmethod
    def get_required_timeframes(self) -> List[Timeframe]:
        raise NotImplementedError

    @abstractmethod
    def get_required_indicators(self) -> List[Indicator]:
        """
        【依赖收集】
        自动收集并合并所有子组件（因子和风险组件）声明的指标依赖。

        这个方法是连接策略配置和DataHandler的关键桥梁。
        """
        all_requests: List[Indicator] = []

        # 将所有可能需要指标的组件放入一个列表中
        components = [self.sizer, self.stop_loss_manager, self.take_profit_manager]

        for component in components:
            # 检查组件是否实现了依赖声明的接口
            if isinstance(component, RequiresIndicators):
                all_requests.extend(component.get_required_indicators())

        # 使用集合 (set) 来自动去重 IndicatorRequest 对象
        unique_requests = list(set(all_requests))

        return unique_requests

    @abstractmethod
    def generate_entry_signal(self, context: Context) -> Optional[Instruction]:
        """
        组合所有因子的输出来生成一个最终的、统一的交易信号。

        这是策略的“大脑”，决定了何时应该考虑入场。

        子类可以重写此方法以实现更复杂的信号组合逻辑，例如：
        - 信号加权求和
        - 信号投票
        - 基于市场状态（如波动率）动态调整因子权重

        Args:
            context (Context): 提供安全历史数据访问的上下文代理。

        Returns:
            Direction: 一个最终的 LONG, SHORT, 或 NEUTRAL 信号。
        """
        # 默认的简化逻辑：采纳第一个非中性的信号
        raise NotImplementedError

    @abstractmethod
    def generate_exit_signal(self, context: Context) -> Optional[Instruction]:
        """
        组合所有因子的输出来生成一个最终的、统一的交易信号。

        这是策略的“大脑”，决定了何时应该考虑入场。

        子类可以重写此方法以实现更复杂的信号组合逻辑，例如：
        - 信号加权求和
        - 信号投票
        - 基于市场状态（如波动率）动态调整因子权重

        Args:
            context (Context): 提供安全历史数据访问的上下文代理。

        Returns:
            Direction: 一个最终的 LONG, SHORT, 或 NEUTRAL 信号。
        """
        # 默认的简化逻辑：采纳第一个非中性的信号
        raise NotImplementedError

    def on_stop_loss(self, position, context: Context) -> Optional[Dict[str, Any]]:
        """
        【事件回调】
        当一个仓位被止损平仓时，回测引擎会调用此方法。

        这是一个“钩子 (hook)”方法，允许子类定义特殊的、状态依赖的行为，
        例如经典的“止损后反转 (Stop and Reverse)”策略。

        Args:
            position: 刚刚被止损的仓位对象。
            context: 当前的市场上下文。

        Returns:
            Optional[Dict[str, Any]]: 
                一个可选的后续交易指令字典。如果返回None，则不执行任何操作。
                如果返回一个指令（例如 {'action': 'OPEN', 'direction': ...}），
                引擎将立即执行它。
        """
        # 默认行为是不执行任何后续操作。
        pass

    # 可以在此添加更多的回调方法，例如：
    def on_take_profit(self, position, context: Context) -> Optional[Dict[str, Any]]:
        pass

    def on_position_opened(self, position, context: Context) -> None:
        pass

    def on_position_closed(self, position, context: Context) -> None:
        pass

    @staticmethod
    def get_max_add_ons() -> int:
        """
        策略的最多加仓次数, 默认为1
        :return: 策略的最多加仓次数
        """
        return 1
